/**
 * Copyright (c) 2005 Frank Toennies
 * Redistributions in source code form must reproduce the above copyright and this condition.
 * The contents of this file are subject to the Sun Project JXTA License Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * A copy of the License is available at http://www.jxta.org/jxta_license.html.
 * Please see the license information page for instructions on use of the license in source files.
 *
 * This software consists of voluntary contributions made by many individuals on behalf of Project JXTA.
 * For more information on Project JXTA, please see http://www.jxta.org.
 *
 */
package net.jxta.myjxta.plugin;

import net.jxta.myjxta.MyJXTA;
import net.jxta.myjxta.ui.UIHelper;
import net.jxta.myjxta.util.Group;

import javax.swing.*;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

public final class DefaultMyJxtaPluginContainer implements PluginContainer, PluginContainer.IPopupGenerator {
    private final MyJXTA m_myJxta;
    private JPopupMenu p_nextPopupMenu = new JPopupMenu();

    private final ArrayList<ISelectionProvider> m_selectionProviders = new ArrayList<ISelectionProvider>();
    private final ArrayList<IPopupProvider> m_popupProvider = new ArrayList<IPopupProvider>();
    private final Plugin[] m_plugins;

    public MyJXTA getMyJxta() {
        return m_myJxta;
    }

    public DefaultMyJxtaPluginContainer(MyJXTA p_myJxta) {
        m_myJxta = p_myJxta;
        try {
            System.setSecurityManager(null);
        } catch (Exception e) {
            e.printStackTrace();
        }


        PluginFetcher.PluginJar[] externalPluginsJars = PluginFetcher.getExternalPluginJars();

        PluginFetcher.PluginJar[] internalPluginsJars = PluginFetcher.getInternalPlugins();

        Plugin[] plugins = PluginFetcher.getValidPluginInstances(externalPluginsJars);
        Plugin[] internalPlugins = PluginFetcher.getValidPluginInstances(internalPluginsJars);
        m_plugins = new Plugin[plugins.length + internalPlugins.length];

        for (int i = 0; i < m_plugins.length; i++) {
            m_plugins[i] = (i < internalPlugins.length) ? internalPlugins[i] : plugins[i - internalPlugins.length];
        }


   }

    public void triggerGlobalMyJxtaPopup(ISelectableNode[] p_selectedNodes, MouseEvent p_e, JComponent p_component) {
        this.p_nextPopupMenu = new JPopupMenu();
        for (Iterator iterator = m_popupProvider.iterator(); iterator.hasNext();) {
            IPopupProvider iPopupProvider = (IPopupProvider) iterator.next();
            iPopupProvider.popupRequested(this, p_selectedNodes, p_e);
        }

        this.p_nextPopupMenu.show(p_component, p_e.getX(), p_e.getY());
    }

    public void registerPopupProvider(IPopupProvider p_component) {
        if (!m_popupProvider.contains(p_component)) {
            m_popupProvider.add(p_component);
        }
    }

    public void removePopupProvider(IPopupProvider p_component) {
        if (m_popupProvider.contains(p_component)) {
            m_popupProvider.remove(p_component);
        }
    }


    public void removeSelectionProvider(ISelectionProvider p_component) {
        if (p_component != null) {
            m_selectionProviders.remove(p_component);
        }

    }

    public void registerSelectionProvider(ISelectionProvider p_component) {
        if (p_component != null && !m_selectionProviders.contains(p_component)) {
            m_selectionProviders.add(p_component);
        }
    }


    public void updateGroupState(Group p_group) {
        for (int i = 0; i < m_plugins.length; i++) {
            Plugin plugin = m_plugins[i];
            try {
                IPluginNotificationHandler pluginNotificationHander = plugin.getPluginNotificationHander();
                if (pluginNotificationHander != null) {
                    pluginNotificationHander.groupStateChanged(p_group);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    public void notifyAboutGroupJoin(Group p_group) {
        for (int i = 0; i < m_plugins.length; i++) {
            Plugin plugin = m_plugins[i];

            IPluginNotificationHandler pluginNotificationHander = plugin.getPluginNotificationHander();
            if (pluginNotificationHander != null) {
                pluginNotificationHander.groupJoined(p_group);
            }
        }
    }

    public void notifyAboutGroupResign(Group p_group) {
        for (int i = m_plugins.length - 1; i >= 0; i--) { //reverse order
            Plugin plugin = m_plugins[i];

            IPluginNotificationHandler pluginNotificationHander = plugin.getPluginNotificationHander();
            if (pluginNotificationHander != null) {
                pluginNotificationHander.groupResigned(p_group);
            }
        }
    }

    public Plugin[] getPlugins() {
        return m_plugins;
    }

    public Plugin getPlugin(Class interfaceClass) {
        for (int i = 0; i < m_plugins.length; i++) {
            Plugin m_plugin = m_plugins[i];
            if (interfaceClass.isAssignableFrom(m_plugin.getClass())){
                return m_plugin;
            }
        }
        return null;
    }

    public void destroy() {
        for (int i = 0; i < m_plugins.length; i++) {
            Plugin plugin = m_plugins[i];
            try {
                plugin.destroy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * getSelectedMyJxtaNodes from the current active component
     *
     * @return
     */
    public ISelectableNode[] getSelectedNodes() {
        ArrayList<ISelectableNode> result = new ArrayList<ISelectableNode>();
        for (Iterator iterator = m_selectionProviders.iterator(); iterator.hasNext();) {
            ISelectionProvider iSelectionProvider = (ISelectionProvider) iterator.next();
            ISelectableNode[] nodes = iSelectionProvider.getSelectedNodes();
            if (nodes != null) {
                for (int i = 0; i < nodes.length; i++) {
                    ISelectableNode node = nodes[i];
                    result.add(node);
                }
            }
        }
        return result.toArray(new ISelectableNode[0]);
    }

    public void addPopup(MenuPath[] path, int section, AbstractAction action) {

        //System.out.println("path:"+path + " "+action.getValue(AbstractAction.NAME));
        JMenu menu = UIHelper.getOrCreateMenuForPath(this.p_nextPopupMenu, path);
        JMenuItem item = null;
        if (menu == null) {
            item = new JMenuItem(action);
            if (!action.isEnabled()) {
                item.setEnabled(false);
            }

            this.p_nextPopupMenu.add(item);
        } else {

            int i = 0;
            int lastSectionNumber = 0;
            while (i < menu.getItemCount()) {
                int index;
                index = i;
                item = menu.getItem(i);


                if (item == null) {
                    item = menu.getItem(i + 1);
                    index++;
                } else {
                }

                lastSectionNumber = getSecNumberOfItem(menu, index);
                if (section < lastSectionNumber) {
                    //insert!
//                        System.out.println(section);
//                        System.out.println(lastSectionNumber);
                    break;
                }

                i++;
            }

            item = new JMenuItem(action);
            item.putClientProperty("MyJxtaMenuSection", new Integer(section));

            insertItemAt(menu, item, i, lastSectionNumber < section);
        }

    }

    private int getSecNumberOfItem(JMenu menu, int index) {
        JMenuItem item = menu.getItem(index);
        return getSecNumberOfItem(item);
    }

    private int getSecNumberOfItem(JMenuItem p_item) {
        Integer sectionNumber = (Integer) p_item.getClientProperty("MyJxtaMenuSection");
        return sectionNumber == null ? -1 : sectionNumber.intValue();
    }

    private void insertItemAt(JMenu menu, JMenuItem p_item, int index, boolean needSep) {
        int ownSectionNumber = getSecNumberOfItem(p_item);
        if (index > 0 && index < menu.getItemCount() && menu.getItem(index) == null) {
            //there is a separator, we want before the sep, but maybe we need one more sep before our element

            if (getSecNumberOfItem(menu, index - 1) < ownSectionNumber) {
                menu.insertSeparator(index);
                index++;
            }
        } else {
            if (needSep) {
                menu.insertSeparator(index);
                index++;
            }
        }


        menu.insert(p_item, index);

    }

    public void init() {
        for (int i = 0; i < m_plugins.length; i++) {
            Plugin plugin = m_plugins[i];
            try {
                plugin.init(this);
            } catch (Throwable e) {
                Logger.getLogger("net.jxta.myjxta.plugin.DefaultMyJxtaPluginContainer").log(Level.SEVERE, "can not init:" + plugin.getClass(), e);
            }
        }
    }


}
